# -*- coding: utf-8 -*-
import json
import os

from PyQt5 import QtCore, QtGui, QtWidgets, Qt
from PyQt5.QtGui import QIcon, QDoubleValidator
from PyQt5.QtWidgets import QDockWidget, QAction, QFileDialog, QGroupBox, QGridLayout
import cv2
import numpy as np
import copy
from imageManager import *

PARA_PATH = os.path.dirname(__file__)


class centerGui(QtWidgets.QWidget):
    update_para_signal = QtCore.pyqtSignal(int, dict)
    para = dict()
    index = 0

    def __init__(self, parent=None):
        super(centerGui, self).__init__(parent)
        self.imgMat = None

    def initPara(self):
        parafile = os.path.join(PARA_PATH, "module_para.json")
        with open(parafile, "r", encoding='utf-8') as f:
            self.para = json.loads(f.read())

    def setPara(self, index, para):
        self.index = index
        if para is None:
            return
        if para["version"] == self.para["version"]:
            self.para = copy.deepcopy(para)
            self.roi_en.setChecked(self.para["roi"]["enable"] == 1)
            self.x_value.setValue(self.para["roi"]["x"])
            self.y_value.setValue(self.para["roi"]["y"])
            self.w_value.setValue(self.para["roi"]["w"])
            self.h_value.setValue(self.para["roi"]["h"])
            self.arcMinText.setValue(self.para["minvalue"])
            self.arcMaxText.setValue(self.para["maxvalue"])

    def initUI(self):
        self.initPara()
        arcMinLabel = QtWidgets.QLabel()
        arcMinLabel.setText("arc minimum length:")
        self.arcMinText = QtWidgets.QSpinBox(self)
        self.arcMinText.setMaximum(655350)
        self.arcMinText.setSingleStep(1)
        self.arcMinText.valueChanged.connect(self.setMinValue)

        hlayout1 = QtWidgets.QHBoxLayout()
        hlayout1.addWidget(arcMinLabel)
        hlayout1.addWidget(self.arcMinText)

        arcMaxLabel = QtWidgets.QLabel()
        arcMaxLabel.setText("arc maximum length:")
        self.arcMaxText = QtWidgets.QSpinBox(self)
        self.arcMaxText.setMaximum(655350)
        self.arcMaxText.setSingleStep(1)
        self.arcMaxText.valueChanged.connect(self.setMaxValue)

        hlayout2 = QtWidgets.QHBoxLayout()
        hlayout2.addWidget(arcMaxLabel)
        hlayout2.addWidget(self.arcMaxText)

        grid = QGridLayout()
        en_lable = QtWidgets.QLabel("enable")
        self.roi_en = QtWidgets.QCheckBox(self)
        x_label = QtWidgets.QLabel("x:")
        self.x_value = QtWidgets.QSpinBox(self)
        y_label = QtWidgets.QLabel("y:")
        self.y_value = QtWidgets.QSpinBox(self)
        w_label = QtWidgets.QLabel("w:")
        self.w_value = QtWidgets.QSpinBox(self)
        h_label = QtWidgets.QLabel("h:")
        self.h_value = QtWidgets.QSpinBox(self)
        grid.addWidget(en_lable, 0, 0)
        grid.addWidget(self.roi_en, 0, 1)
        grid.addWidget(x_label, 1, 0)
        grid.addWidget(self.x_value, 1, 1)
        grid.addWidget(y_label, 2, 0)
        grid.addWidget(self.y_value, 2, 1)
        grid.addWidget(w_label, 1, 2)
        grid.addWidget(self.w_value, 1, 3)
        grid.addWidget(h_label, 2, 2)
        grid.addWidget(self.h_value, 2, 3)
        groupBox = QGroupBox("Region of Interest:")
        groupBox.setLayout(grid)

        btn_apply = QtWidgets.QPushButton()
        btn_apply.setText("apply")

        btn_ok = QtWidgets.QPushButton(self)
        btn_ok.setText("ok")
        btn_ok.clicked.connect(self.btn_ok_clicked)

        btn_cancel = QtWidgets.QPushButton(self)
        btn_cancel.setText("cancel")
        btn_cancel.clicked.connect(self.btn_cancel_clicked)
        hbox_common = QtWidgets.QHBoxLayout()
        hbox_common.addWidget(btn_ok)
        hbox_common.addWidget(btn_cancel)

        vlayout = QtWidgets.QVBoxLayout(self)
        vlayout.addLayout(hlayout1, 1)
        vlayout.addLayout(hlayout2)
        vlayout.addWidget(groupBox)
        vlayout.addStretch(1)
        vlayout.addWidget(btn_apply)
        vlayout.addLayout(hbox_common)
        btn_apply.clicked.connect(self.btn_apply_clicked)
        self.x_value.setRange(0, 65535)
        self.y_value.setRange(0, 65535)
        self.w_value.setRange(0, 65535)
        self.h_value.setRange(0, 65535)
        self.x_value.valueChanged.connect(self.x_value_changed)
        self.y_value.valueChanged.connect(self.y_value_changed)
        self.w_value.valueChanged.connect(self.w_value_changed)
        self.h_value.valueChanged.connect(self.h_value_changed)
        self.roi_en.stateChanged.connect(self.enable_value_changed)

    def setMinValue(self):
        self.para["minvalue"] = self.arcMinText.value()

    def setMaxValue(self):
        self.para["maxvalue"] = self.arcMaxText.value()

    def zoneChange(self, zone):
        self.para["roi"]["x"] = zone[0]
        self.para["roi"]["y"] = zone[1]
        self.para["roi"]["w"] = zone[2]
        self.para["roi"]["h"] = zone[3]
        self.drawROI()
        self.x_value.setValue(self.para["roi"]["x"])
        self.y_value.setValue(self.para["roi"]["y"])
        self.w_value.setValue(self.para["roi"]["w"])
        self.h_value.setValue(self.para["roi"]["h"])

    def enable_value_changed(self):
        if self.roi_en.isChecked():
            self.para["roi"]["enable"] = 1
        else:
            self.para["roi"]["enable"] = 0
        self.drawROI()

    def x_value_changed(self):
        self.para["roi"]["x"] = self.x_value.value()
        self.drawROI()

    def y_value_changed(self):
        self.para["roi"]["y"] = self.y_value.value()
        self.drawROI()

    def w_value_changed(self):
        self.para["roi"]["w"] = self.w_value.value()
        self.drawROI()

    def h_value_changed(self):
        self.para["roi"]["h"] = self.h_value.value()
        self.drawROI()

    def drawROI(self):
        if self.para["roi"]["enable"] == 0:
            return
        img = img_mng.getOriginMat()
        if img is None:
            return
        if len(img.shape) == 3:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        else:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        x = self.para["roi"]["x"]
        y = self.para["roi"]["y"]
        w = self.para["roi"]["w"]
        h = self.para["roi"]["h"]
        cv2.rectangle(self.imgMat, (x, y), (x + w, y + h), (0, 255, 0), 5)
        img_mng.dispImg(self.imgMat)

    def btn_apply_clicked(self):
        img = img_mng.getOriginMat()
        if img is None:
            return
        if len(img.shape) == 3:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        else:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        enable = self.para["roi"]["enable"]
        if enable == 1:
            x = self.para["roi"]["x"]
            y = self.para["roi"]["y"]
            w = self.para["roi"]["w"]
            h = self.para["roi"]["h"]

            mask = np.zeros_like(img_mng.img)
            mask[y:(y + h), x:(x + w)] = 255
            imgray = cv2.bitwise_and(img_mng.img, mask)
        else:
            imgray = img_mng.img

        # img_mng.showImg("masked.jpg", imgray)

        contours, hierarchy = cv2.findContours(imgray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        len_contours = len(contours)
        arclen_min = self.para["minvalue"]
        arclen_max = self.para["maxvalue"]
        for i in range(len_contours):
            arclen = cv2.arcLength(contours[i], True)
            if arclen_min < arclen < arclen_max:
                # color format: (B G R)
                cv2.drawContours(self.imgMat, contours, i, (0, 0, 255), 5)
                # ret = cv2.minEnclosingCircle(contours[i])
                # print("minEnclosingCircle:((x,y),radius)", ret)
                points = len(contours[i])
                if points < 5:
                    continue
                e1 = cv2.getTickCount()
                ret = cv2.fitEllipse(contours[i])
                e2 = cv2.getTickCount()
                time = (e2 - e1) / cv2.getTickFrequency()
                print("fitEllipse:(center, width, height, angle)", ret)
                print("elapse time:", time*1000, "ms")
        img_mng.dispImg(self.imgMat)

    def btn_ok_clicked(self):
        self.para["minvalue"] = int(self.arcMinText.text())
        self.para["maxvalue"] = int(self.arcMaxText.text())
        self.update_para_signal.emit(self.index, self.para)

    def btn_cancel_clicked(self):
        self.close()

    def run(self, para):
        img = img_mng.getOriginMat()
        if img is None:
            return
        if len(img.shape) == 3:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        else:
            self.imgMat = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
        enable = self.para["roi"]["enable"]
        if enable == 1:
            x = self.para["roi"]["x"]
            y = self.para["roi"]["y"]
            w = self.para["roi"]["w"]
            h = self.para["roi"]["h"]

            mask = np.zeros_like(img_mng.img)
            mask[y:(y + h), x:(x + w)] = 255
            imgray = cv2.bitwise_and(img_mng.img, mask)
        else:
            imgray = img_mng.img
        contours, hierarchy = cv2.findContours(imgray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        len_contours = len(contours)
        arclen_min = para["minvalue"]
        arclen_max = para["maxvalue"]
        for i in range(len_contours):
            arclen = cv2.arcLength(contours[i], True)
            if arclen_min < arclen < arclen_max:
                # color format: (B G R)
                cv2.drawContours(self.imgMat, contours, i, (0, 0, 255), 3)
                # ret = cv2.fitEllipse(contours[i])
                # print("fitEllipse:((x,y),(a,b),angle)", ret)
                ret = cv2.minEnclosingCircle(contours[i])
                print("minEnclosingCircle:((x,y),radius)", ret)
                ret = cv2.fitEllipse(contours[i])
                print("fitEllipse:(center, width, height, angle)", ret)
                xc, yc = ret[0]
                r = ret[1]
                rr = np.power(r, 2)
                ret_p = []
                min_dd = 6553500
                notch_p = []
                for p in contours[i]:
                    x, y = p[0]
                    dd = np.power(x - xc, 2) + np.power(y - yc, 2)
                    if min_dd > dd:
                        min_dd = dd
                        notch_p = p[0]
                        # print("dd", dd, x, y)
                    if dd < rr:
                        ret_p.append(p)
                print("notch", notch_p)
        img_mng.dispImg(self.imgMat)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    ui = centerGui()
    ui.initUI()
    ui.show()
    sys.exit(app.exec_())
